﻿using System;
using System.Runtime.CompilerServices;

namespace Nsb.Classes
{
    [IgnoreNamespace]
    public static class Formulas
    {
        private static int _idCnt;
        public static string NewIdPrefix;

        /// <summary>
        /// Generate a new unique id composed of [user]q[time]n[count]
        /// </summary>
        /// <remarks>
        /// Where [count] recycles after 99999 since the time will always be different
        /// after 99999 accesses even on a very fast computer (I believe).
        /// </remarks>
        public static string NewId
        {
            get { return (NewIdPrefix ?? RandomOf(10000000).ToString()) + "q" + (new Date()).GetTime() + "n" + (_idCnt = _idCnt > 99999 ? 1 : _idCnt + 1); }
        }

        public static int RandomOf(int max)
        {
            return Math.Floor(Math.Random()*(max + 1));
        }

        public static int Hash(string s)
        {
            int hash = 0;

            for (int i = 0; i < s.Length; i++)
            {
                hash += (s.CharCodeAt(i)*(i + 1));
            }
            return Math.Abs(hash);
        }

        //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
        //:::                                                                         :::
        //:::  This routine calculates the distance between two points (given the     :::
        //:::  latitude/longitude of those points). It is being used to calculate     :::
        //:::  the distance between two ZIP Codes or Postal Codes using our           :::
        //:::  ZIPCodeWorld(TM) and PostalCodeWorld(TM) products.                     :::
        //:::                                                                         :::
        //:::  Definitions:                                                           :::
        //:::    South latitudes are negative, east longitudes are positive           :::
        //:::                                                                         :::
        //:::  Passed to function:                                                    :::
        //:::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :::
        //:::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :::
        //:::    unit = the unit you desire for results                               :::
        //:::           where: 'M' is statute miles                                   :::
        //:::                  'K' is kilometers (default)                            :::
        //:::                  'N' is nautical miles                                  :::
        //:::                                                                         :::
        //:::  United States ZIP Code/ Canadian Postal Code databases with latitude   :::
        //:::  & longitude are available at http://www.zipcodeworld.com               :::
        //:::                                                                         :::
        //:::  For enquiries, please contact sales@zipcodeworld.com                   :::
        //:::                                                                         :::
        //:::  Official Web site: http://www.zipcodeworld.com                         :::
        //:::                                                                         :::
        //:::  Hexa Software Development Center © All Rights Reserved 2004            :::
        //:::                                                                         :::
        //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

        [AlternateSignature]
        public static extern double Distance(double lat1, double lon1, double lat2, double lon2);

        public static double Distance(double lat1, double lon1, double lat2, double lon2, string unit)
        {
            double radlat1 = Math.PI*lat1/180;
            double radlat2 = Math.PI*lat2/180;
            double theta = lon1 - lon2;
            double radtheta = Math.PI*theta/180;
            double dist = Math.Sin(radlat1)*Math.Sin(radlat2) + Math.Cos(radlat1)*Math.Cos(radlat2)*Math.Cos(radtheta);
            dist = Math.Acos(dist);
            dist = dist*180/Math.PI;
            dist = dist*60*1.1515;
            if (unit == "K")
            {
                dist = dist*1.609344;
            }
            else if (unit == "N")
            {
                dist = dist*0.8684;
            }
            return dist;
        }
    }
}